import { Component, OnInit, ViewChild, Input, Output, EventEmitter, HostBinding, NgZone, AfterViewInit, OnDestroy } from '@angular/core';
import { TreeTableComponent, TreeNode } from '@farris/ui-treetable';
import { FieldTreeTableService } from './field-treetable.service';
import { NotifyService } from '@farris/ui-notify';
import { cloneDeep } from 'lodash-es';
import { constants, ContainerOptions, DropResult, smoothDnD } from '@farris/smooth-dnd';
import { DomService, DesignViewModelService, DgControl, FormBasicService, DesignerEnvType } from '@farris/designer-services';
import { IdService } from '@farris/ui-common';


@Component({
  selector: 'app-field-treetable',
  templateUrl: './field-treetable.component.html',
  styleUrls: ['./field-treetable.component.css']
})

export class FieldTreeTableComponent implements OnInit, AfterViewInit, OnDestroy {
  @Input() viewModelId;

  @Input() treeCols = [];
  @Input() idField = 'id';
  @Output() viewModelChanged = new EventEmitter<any>();
  // 从左至右拖拽添加字段
  @Output() addFieldDropped = new EventEmitter<any>();

  // @Output() selectRowEvent = new EventEmitter<any>();

  @HostBinding('class')
  cls = 'd-block h-100 f-utils-overflow-auto';

  @ViewChild('treeTable') treeTable: TreeTableComponent;
  treeData = [];
  fieldCount = 0;
  selectedNode: TreeNode | any;

  noDataMoveMessage = '请选择要移动的数据。';
  noDataGroupMessage = '请选择要分组的数据。';
  noDataRemoveGroupMessage = '请选择要解除分组的数据。';
  get checkedNodes() {
    return this.treeTable.checkeds;
  }

  dgViewModel;
  constructor(
    private domServ: DomService,
    private fieldTreeServ: FieldTreeTableService,
    private notifyServ: NotifyService,
    private dgViewModelServ: DesignViewModelService,
    private idService: IdService,
    private ngZone: NgZone,
    private formBasicServ: FormBasicService) {

  }
  ngOnInit() {
    this.initData();
    this.dgViewModel = this.dgViewModelServ.getDgViewModel(this.viewModelId);
  }

  ngAfterViewInit() {
    this.makeTargetTreeDraggable();
  }
  ngOnDestroy() {
    if (this['targetTreeContainer']) {
      this['targetTreeContainer'].dispose();
    }
  }
  initData() {
    const cmp = this.domServ.getComponentByVMId(this.viewModelId);

    // this.treeData = this.fieldTreeServ.assembleFieldTreeData(cmp.viewModel);
    this.treeData = this.fieldTreeServ.buildFieldTreeData(cmp.viewModel);


  }

  /**
   * 获取绑定字段展示文本
   * @param rowNode 行数据
   */
  getBindingFieldInfo(rowNode: any) {
    if (rowNode.node.isRemoved) {
      return '[绑定字段不存在，请手动移除控件]';
    }
    if (rowNode.node.isBindVariable) {
      return '[变量：' + rowNode.node.data.code + ']';
    }
    if (rowNode.node.isComplexField) {
      return '[请手动移除控件，添加关联字段节点]';
    }
    if (rowNode.node.isNoBinding) {
      return '[控件没有绑定信息]';
    }
    if (rowNode.node.isGroupNode) {
      return '';
    }
    return '[' + rowNode.node.data.bindingField + ']';
  }
  /**
   * 选中行
   * @param rowNode 行数据
   */
  selectNode(rowNode: any) {
    this.selectedNode = rowNode.node;
    // this.selectRowEvent.emit(this.selectedNode);
  }
  unSelectNode(rowNode) {
    this.selectedNode = null;
  }
  deleteFields() {

  }

  /**
   * 新增字段
   * @param fields 字段
   */
  addFields(leftChecks: any[]) {
    const fieldCountBeforeAdd = this.treeData.length;
    const vmAdded = [];
    leftChecks.forEach(checkNode => {
      this.treeData.push({ data: checkNode.data, children: [], rtRelateSchemaField: checkNode.rtRelateSchemaField });
      vmAdded.push(checkNode.data);
    });
    this.treeTable.loadData(this.treeData);

    // 若右侧树数据从0变成1时，tbody节点会被重绘，所以要重新配置拖拽逻辑
    if (fieldCountBeforeAdd === 0) {
      this.makeTargetTreeDraggable();
    }
  }

  /**
   * 删除字段
   * @param fields 字段
   */
  removeFields() {
    let checkeds = this.treeTable.checkeds as TreeNode[] | any[];
    if (!checkeds || checkeds.length === 0) {
      this.notifyServ.warning(this.noDataMoveMessage);
      return;
    }
    checkeds = this.checkRTControl(checkeds);
    if (checkeds.length === 0) {
      this.treeTable.checkeds = [];
      this.treeTable.loadData(this.treeData);
      return;
    }
    const vmChanges = {};
    checkeds.forEach((element: any) => {
      // 跳过分组节点
      if (element.isGroupNode) {
        return;
      }
      // 在根节点下删除
      if (!element.parent) {
        const nodeIndex = this.treeData.findIndex(node => node.data.id === element.data.id);
        this.treeData.splice(nodeIndex, 1);
      } else {
        // 分组节点下删除
        const nodeIndex = element.parent.children.findIndex(node => node.data.id === element.data.id);
        element.parent.children.splice(nodeIndex, 1);

        // 分组节点下没有字段则自动删除分组节点
        if (element.parent.children.length === 0) {
          const groupId = this.treeData.findIndex(node => node.data.id === element.parent.data.id);
          this.treeData.splice(groupId, 1);
        }

        vmChanges[element.data.id] = {
          groupId: null,
          groupName: null
        };
      }
      // 若当前节点为行选中节点，需要清空选中行记录
      if (this.selectedNode && element.data.id === this.selectedNode.data.id) {
        this.selectedNode = null;
      }
    });
    this.treeTable.checkeds = [];
    this.treeTable.loadData(this.treeData);
    if (this.selectedNode) {
      // 重新选中行
      const rowNode = this.treeTable.findRowNode(this.selectedNode.data.id);
      if (rowNode) {
        rowNode.isSelected = true;
      }
    } else {
      this.treeTable.clearAll();
    }
    this.viewModelChanged.emit(vmChanges);

    // 若右侧树没有数据，那么treetable会重绘tbody节点，这样之前配置的拖拽逻辑就会被丢弃，所以要支持拖拽接收字段的话，就需要重新配置拖拽
    if (this.treeData.length === 0) {
      this.makeTargetTreeDraggable();
    }
  }

  /**
   * 不允许移除基础表单控件
   * @param checkes 选中的字段
   */
  private checkRTControl(selectedNodes: TreeNode[] | any[]): TreeNode[] {
    if (this.formBasicServ.envType !== DesignerEnvType.runtimeCustom) {
      return selectedNodes;
    }
    const basicNames = [];
    selectedNodes.forEach((node: any) => {
      if (!node.control || node.control.type === DgControl.FieldSet.type) {
        return;
      }
      if (!node.control.isRTControl) {
        basicNames.push(node.data.name);
      }
    });
    selectedNodes = selectedNodes.filter((node: any) => !node.control || node.control.isRTControl);
    if (basicNames.length) {
      this.notifyServ.warning('【' + basicNames.join('、') + '】是基础表单控件，不允许移除。');
    }
    return selectedNodes;
  }

  /**
   * 删除所有字段
   */
  removeAllFields() {
    const isRtEnvType = this.formBasicServ.envType === DesignerEnvType.runtimeCustom;
    const plainNodes = this.treeTable.serializedValue;
    const plainTreeNodes = plainNodes.map(row => row.node) as TreeNode[] | any[];

    const treeData = cloneDeep(this.treeData);
    const basicNames = [];
    const vmChanges = {};
    plainTreeNodes.forEach((node: any) => {
      if (node.isGroupNode) {
        return;
      }
      // 基础表单控件
      if (isRtEnvType && node.control && !node.control.isRTControl) {
        basicNames.push(node.data.name);
        return;
      }

      // 在根节点下删除
      if (!node.parent) {
        const nodeIndex = treeData.findIndex(n => node.data.id === n.data.id);
        treeData.splice(nodeIndex, 1);
      } else {
        // 分组节点下删除
        const groupNodeIndex = treeData.findIndex(n => n.data.id === node.parent.data.id);
        const groupNode = treeData[groupNodeIndex];
        const nodeIndex = groupNode.children.findIndex(n => n.data.id === node.data.id);
        groupNode.children.splice(nodeIndex, 1);

        // 分组节点下没有字段则自动删除分组节点
        if (groupNode.children.length === 0) {
          treeData.splice(groupNodeIndex, 1);
        }

        vmChanges[node.data.id] = {
          groupId: null,
          groupName: null
        };
      }
    });

    if (basicNames.length) {
      this.notifyServ.warning('【' + basicNames.join('、') + '】是基础表单控件，不允许移除。');
    }
    this.treeData = treeData;
    this.treeTable.loadData(treeData);
    this.treeTable.clearAll();
    this.selectedNode = null;

    this.viewModelChanged.emit(vmChanges);

    // 若右侧树没有数据，那么treetable会重绘tbody节点，这样之前配置的拖拽逻辑就会被丢弃，所以要支持拖拽接收字段的话，就需要重新配置拖拽
    if (treeData.length === 0) {
      this.makeTargetTreeDraggable();
    }

  }
  /**
   * 置顶
   */
  moveTop() {
    if (!this.selectedNode) {
      this.notifyServ.warning(this.noDataMoveMessage);
      return;
    }
    const curEle = this.selectedNode;
    const parentNode = curEle.parent;
    const parentData = parentNode ? parentNode.children : this.treeData; // 在根节点上移动 or 分组节点上移动
    const index = parentData.findIndex(node => node.data.id === curEle.data.id);
    // 1、顶级节点 ====> 不动
    if (index < 1 && !parentNode) {
      return;
    }
    const vmChanges = {};
    parentData.splice(index, 1);
    this.treeData.splice(0, 0, curEle);

    // 2、分组节点内的节点
    if (parentNode && parentNode.isGroupNode) {
      curEle.parent = null;
      vmChanges[curEle.id] = {
        groupId: null,
        groupName: null
      };
      // 分组下没有控件了==>移除分组
      if (parentNode.children.length === 0) {
        const groupIndex = this.treeData.findIndex(node => node.data.id === parentNode.data.id);
        this.treeData.splice(groupIndex, 1);
      }
    }

    this.treeTable.loadData(this.treeData);

    this.viewModelChanged.emit(vmChanges);
  }

  /**
   * 上移
   */
  moveUp() {

    if (!this.selectedNode) {
      this.notifyServ.warning(this.noDataMoveMessage);
      return;
    }
    const curEle = this.selectedNode;
    const parentNode = curEle.parent;
    const parentData = parentNode ? parentNode.children : this.treeData; // 在根节点上移动 or 分组节点上移动
    const index = parentData.findIndex(node => node.data.id === curEle.data.id);
    // 1、顶级节点 ====> 不动
    if (index < 1 && !parentNode) {
      return;
    }
    const vmChanges = {};
    // 2、分组节点内的第一个节点 ===> 移出分组
    if (index < 1 && parentNode && parentNode.isGroupNode) {
      parentData.splice(0, 1);
      const parentIndex = this.treeData.findIndex(node => node.data.id === parentNode.data.id);
      curEle.parent = null;
      this.treeData.splice(parentIndex, 0, curEle);
      vmChanges[curEle.id] = {
        groupId: null,
        groupName: null
      };
      // 分组下没有字段了: 删除分组
      if (parentData.length === 0) {
        this.treeData.splice(parentIndex + 1, 1);
      }
    } else {
      const preEle = parentData[index - 1];
      parentData.splice(index, 1);

      if (preEle.children && preEle.children.length > 0 && !curEle.isGroupNode) {
        // 3、上一个节点是分组且当前不是分组节点 ===> 移动到分组内
        curEle.parent = preEle;
        preEle.children.push(curEle);
        vmChanges[curEle.id] = {
          groupId: preEle.data.id,
          groupName: preEle.data.name
        };
      } else {
        // 4、同级移动
        parentData.splice(index - 1, 0, curEle);
      }
    }


    this.treeTable.loadData(this.treeData);


    this.viewModelChanged.emit(vmChanges);
  }
  /**
   * 下移
   */
  moveDown() {
    if (!this.selectedNode) {
      this.notifyServ.warning(this.noDataMoveMessage);
      return;
    }
    const curEle = this.selectedNode;
    const parentNode = curEle.parent;
    const parentData = parentNode ? parentNode.children : this.treeData; // 在根节点上移动 or 分组节点上移动
    const index = parentData.findIndex(node => node.data.id === curEle.data.id);
    // 1、顶级节点的最后一个====> 不动
    if (index === parentData.length - 1 && !parentNode) {
      return;
    }

    const vmChanges = {};
    // 2、分组节点内的最后一个节点 ====> 移出分组
    if (index === parentData.length - 1 && parentNode && parentNode.isGroupNode) {
      parentData.splice(index, 1);
      curEle.parent = null;
      const parentIndex = this.treeData.findIndex(node => node.data.id === parentNode.data.id);
      this.treeData.splice(parentIndex + 1, 0, curEle);
      vmChanges[curEle.id] = {
        groupId: null,
        groupName: null
      };
      // 分组下没有字段了: 删除分组
      if (parentData.length === 0) {
        this.treeData.splice(parentIndex, 1);
      }
    } else {
      const nextEle = parentData[index + 1];

      parentData.splice(index, 1);
      // 3、下一个节点是分组且当前不是分组节点 ===> 移动到分组内
      if (nextEle.children && nextEle.children.length > 0 && !curEle.isGroupNode) {
        nextEle.children.splice(0, 0, curEle);
        curEle.parent = nextEle;
        vmChanges[curEle.id] = {
          groupId: nextEle.data.id,
          groupName: nextEle.data.name
        };
      } else {
        // 4、同级移动
        parentData.splice(index + 1, 0, curEle);
      }
    }


    this.treeTable.loadData(this.treeData);

    this.viewModelChanged.emit(vmChanges);
  }

  /**
   * 置底
   */
  moveBottom() {
    if (!this.selectedNode) {
      this.notifyServ.warning(this.noDataMoveMessage);
      return;
    }

    const curEle = this.selectedNode;
    const parentNode = curEle.parent;
    const parentData = parentNode ? parentNode.children : this.treeData; // 在根节点上移动 or 分组节点上移动
    const index = parentData.findIndex(node => node.data.id === curEle.data.id);

    // 1、顶级节点的最后一个 ====> 不动
    if (index === parentData.length - 1 && !parentNode) {
      return;
    }
    parentData.splice(index, 1);
    this.treeData.push(curEle);

    // 分组节点内的
    const vmChanges = {};
    if (parentNode && parentNode.isGroupNode) {
      curEle.parent = null;
      vmChanges[curEle.id] = {
        groupId: null,
        groupName: null
      };

      // 分组下没有控件了==>移除分组
      if (parentNode.children.length === 0) {
        const groupIndex = this.treeData.findIndex(node => node.data.id === parentNode.data.id);
        this.treeData.splice(groupIndex, 1);
      }
    }

    this.treeTable.loadData(this.treeData);

    this.viewModelChanged.emit(vmChanges);
  }

  addGroup() {
    const checkeds = this.treeTable.checkeds as TreeNode[] | any;
    if (!checkeds || checkeds.length === 0) {
      this.notifyServ.warning(this.noDataGroupMessage);
      return;
    }
    for (const element of checkeds) {
      if (element.parent) {
        this.notifyServ.warning('字段【' + element.data.name + '】已分组，不可再次分组！');
        return;
      }
      if (element.isGroupNode) {
        this.notifyServ.warning('分组节点不可再次分组！');
        return;
      }
      if (element.isBindVariable) {
        this.notifyServ.warning('绑定变量的控件不支持分组！');
        return;
      }
      if (element.isNoBinding) {
        this.notifyServ.warning('没有绑定信息的控件不支持分组！');
        return;
      }
    }
    const selectedIdList = this.treeTable.checkeds.map(ele => ele.data.id);
    // treeData中删除选中字段
    this.treeData = this.treeData.filter(treeNode => !selectedIdList.includes(treeNode.data.id));

    // 新增分组字段
    const groupId = this.idService.generate();
    const groupNode = {
      data: {
        id: groupId,
        code: '',
        name: '新增分组'
      },
      children: this.treeTable.checkeds,
      expanded: true,
      isGroupNode: true
    };
    this.treeData.push(groupNode);
    this.treeTable.checkeds = [];


    // 修改VM
    const vmChanges = {};
    selectedIdList.forEach(id => {
      vmChanges[id] = {
        groupId,
        groupName: '新增分组'
      };
    });
    this.viewModelChanged.emit(vmChanges);
  }


  /**
   * 解除分组
   */
  removeGroup() {
    const checkeds = this.treeTable.checkeds as TreeNode[] | any;
    if (!checkeds || checkeds.length === 0) {
      this.notifyServ.warning(this.noDataRemoveGroupMessage);
      return;
    }

    const selectedIdList = [];
    for (const element of checkeds) {
      // 1、分组下的节点：父节点未选中时，从分组中移除并添加到根节点；若父节点已选中，则跳过
      if (element.parent && element.children.length === 0) {
        const isParentSelected = checkeds.findIndex(se => se.data.id === element.parent.data.id);
        if (isParentSelected < 0) {
          const nodeIndex = element.parent.children.findIndex(node => node.data.id === element.data.id);
          element.parent.children.splice(nodeIndex, 1);
          const { parent, ...nodeInfo } = element;
          this.treeData.push(nodeInfo);
          if (parent.children.length === 0) {
            const groupId = this.treeData.findIndex(node => node.data.id === parent.data.id);
            this.treeData.splice(groupId, 1);
          }

          selectedIdList.push(element.data.id);
        }
      }

      // 2、分组节点：移除分组节点并将其下的节点移动到根节点下
      if (element.isGroupNode) {
        this.treeData = this.treeData.filter(treeNode => element.data.id !== treeNode.data.id);

        const childNodes = element.children;
        childNodes.map(treeNode => {
          const { parent, ...nodeInfo } = treeNode;
          this.treeData.push(nodeInfo);
          selectedIdList.push(treeNode.data.id);
        });
        // 当前选中的是分组节点: 清空属性面板
        if (this.selectedNode && element.data.id === this.selectedNode.data.id) {
          this.selectedNode = null;
        }
      }

      // 3、根节点下未分组的字段：给出提示
      if (!element.parent && !element.isGroupNode) {
        this.notifyServ.warning('字段【' + element.data.name + '】未分组！');
      }

      element.parent = null;
    }
    this.treeTable.checkeds = [];
    this.treeTable.loadData(this.treeData);

    // 重新选中行
    if (this.selectedNode) {
      const rowNode = this.treeTable.findRowNode(this.selectedNode.data.id);
      if (rowNode) {
        rowNode.isSelected = true;
      }
    } else {
      this.treeTable.clearAll();
    }

    // 修改VM
    const vmChanges = {};
    selectedIdList.forEach(id => {
      vmChanges[id] = {
        groupId: null,
        groupName: null
      };
      // 当前选中行: 修改parent
      if (this.selectedNode && id === this.selectedNode.data.id) {
        this.selectedNode.parent = null;
      }
    });
    this.viewModelChanged.emit(vmChanges);
  }
  /**
   * 字段拖拽
   */
  onDrop(dropResult: DropResult) {
    if (dropResult.removedIndex !== null) {
      // 在右侧树中上下拖拽----暂不考虑
      // this.dragInsideTargetTree(dropResult);

    } else {
      // 从左侧树拖字段至右侧树
      this.dragFromSourceTreeToTargetTree(dropResult);
    }
  }

  // dragInsideTargetTree({ removedIndex, addedIndex, payload }: DropResult) {

  //     if (removedIndex === null) {
  //         return;
  //     }
  //     const movedNode = this.treeTable.serializedValue.find(v => v.index === removedIndex);
  //     const targetNode = this.treeTable.serializedValue.find(v => v.index === addedIndex);
  //     if (!movedNode.parent) {
  //         // 被移动节点在根节点下
  //         const movedNodeIndex = this.treeData.findIndex(d => d.id === movedNode.id);
  //         if (!targetNode.parent) {
  //             // 目标位置在根节点下--- 同级移动
  //             this.treeData.splice(movedNodeIndex, 1);
  //             const targetNodeIndex = this.treeData.findIndex(d => d.id === targetNode.id);
  //             // if (movedNodeIndex > targetNodeIndex) {
  //             this.treeData.splice(targetNodeIndex, 0, payload);

  //             // } else {

  //             // }
  //         }
  //     }

  //     this.treeTable.loadData(this.treeData);

  // }

  /**
   * 从左侧树拖字段至右侧树
   */
  dragFromSourceTreeToTargetTree({ addedIndex, payload }: DropResult) {
    if (addedIndex === null || !payload) {
      return;
    }
    const fieldCountBeforeDrag = this.treeData.length;
    const targetNode = this.treeTable.serializedValue.find(v => v.index === addedIndex);
    if (!targetNode) {
      // 拖拽到最后一个节点下面
      this.treeData.push({ data: payload, children: [] });
    } else {
      const parentNode = targetNode.parent;
      if (!parentNode) {
        // 拖拽到根节点下
        const targetIndex = this.treeData.findIndex(d => d.id === targetNode.id);
        this.treeData.splice(targetIndex, 0, { data: payload, children: [] });

      } else {
        // 拖拽到分组内
        const newData = Object.assign({},
          payload, {
          groupId: parentNode.data.id,
          groupName: parentNode.data.name
        });
        const targetIndex = parentNode.children.findIndex(d => d.id === targetNode.id);
        parentNode.children.splice(targetIndex, 0, { data: newData, children: [] });
      }
    }

    this.treeTable.loadData(this.treeData);

    this.addFieldDropped.emit();


    if (fieldCountBeforeDrag === 0) {
      this.makeTargetTreeDraggable();
    }
  }

  /**
   * 配置右侧树可拖拽
   */
  private makeTargetTreeDraggable() {

    this.ngZone.runOutsideAngular(() => {
      setTimeout(() => {
        const tbodyList = this.treeTable.el.nativeElement.getElementsByTagName('tbody');
        if (!tbodyList.length) {
          return;
        }
        const containerElement = tbodyList[0];

        const containerOptions: ContainerOptions = {
          groupName: 'selectColumn',
          nonDragAreaSelector: '[ng-reflect-enable-dbl-click=true]',
          onDrop: this.onDrop.bind(this)
        };
        // tslint:disable-next-line:no-string-literal
        this['targetTreeContainer'] = smoothDnD(containerElement, containerOptions);

        const children = containerElement.children;

        Array.prototype.forEach.call(children, (item: HTMLElement) => {
          item.classList.add(constants.wrapperClass);
        });
      });
    });

  }

}
